/* Inverse schedule estimation algorithm */

#include <stdio.h>
#include <stdlib.h>

#include "itf_debug.h"

#include "prefix_tree.h"
#include "path.h"
#include "mex.h"


int exists(ntrie *child, int ev_id) {
    
    ntrieNode node_nt;
    
    node_nt.node = NULL;
    node_nt.key = ev_id;
    
    /*mexPrintf("exists funtion init ...\n");*/
    
    /* Find */
    if (NEDTRIE_FIND(ntrie_s, child, &node_nt) == NULL)
        return 0;
    else
        return 1;
}

int replace(clock_l *clkList, double oldclk, double newclk) {
    clock_n *node;
    
    for(node = clkList->firstNode;node != NULL; node = node->next) {
        if (*(node->data) == oldclk) {
            *(node->data) = newclk;
            
            /*clock_debug(clkList, clkList->firstNode);*/
            
            return 1;
        }
    }
    
    return 0;
}

int size(ntrie *child) {
    return child->count;
}

/*path_n *find_mns(path_n *node, int ev_id) {
    
    
    for(; node != NULL; node = node->prev) {
        
        mexPrintf("%d <- (%d) %f ", node->data.ev_id, ev_id, node->data.clk);
        
        if (node->data.ev_id == 0)
            return node;
        
        mexPrintf("Finding...\n");
        assert(node->data.t_node != NULL);
        assert(node->data.t_node != NULL);
        
        mexPrintf("%d %d %d Event: %d\n", exists(node->data.t_node->child, ev_id), (size(node->data.t_node->child) > 1), node->data.ev_id != ev_id, ev_id);
        
        if (exists(node->data.t_node->child, ev_id) && (size(node->data.t_node->child) > 1) && node->data.ev_id != ev_id)
            continue;
        else
            return node;
    }
    
    return NULL;
}*/

path_n *pathfind(path_n *prevnode, path_n *node, int ev_id){
    
    if (prevnode->data.ev_id == 0)
            return node;
    
    /*mexPrintf("(%d and %d and %d) %d\n", exists(prevnode->data.t_node->child, ev_id), (size(prevnode->data.t_node->child) > 1), prevnode->data.ev_id != ev_id, ev_id);*/
    
    if (exists(prevnode->prev->data.t_node->child, ev_id) && (size(prevnode->prev->data.t_node->child) > 1) && prevnode->data.ev_id != ev_id)
        return pathfind(prevnode->prev, prevnode, ev_id);
    else
        return node;
}

double orig_clksv(path_n *path, path_n *node) {
    path_n *tmp_node = node;
    double value = 0;
    
    for(; tmp_node != NULL;) {
        
        value = value + tmp_node->data.clk;
        
        if (tmp_node == path)
            return value;
        
        tmp_node = tmp_node->next;
    }
    
    return -1;
    
}

/* path is a sequence of events, and paths is a set of paths*/
void ise_algorithm(psa *trie, path_l **paths, int n_paths) {
    
    int i, j;
    path_n *path;
    path_n *nodeM;
    /*evnode *node;*/
    
    double value;
    
    for (i=0; i<n_paths; i++) {
        
        if (!(paths[i]->n-1 > 2))
            continue;
        
        DEBUG_PRINT((FDEBUG, "---- ISE ALgorithm - Start ...\n"));
        DEBUG_PRINT((FDEBUG, "Path size: %d; Id: %d\n", paths[i]->n-1, i+1));
        
        /* Path debug*/
        /*path_debug(paths[i], paths[i]->firstNode);*/
        
        for(j=0, path = paths[i]->firstNode->next->next; path != NULL; path = path->next, j++) {
            
            DEBUG_PRINT((FDEBUG, "%d\n", j));
            
            assert(path->data.t_node != NULL);
            assert(path->prev != NULL);
            assert(path->prev->data.t_node != NULL);
            
            DEBUG_PRINT((FDEBUG, "Iteration %d, Event %d, Path: %p\n", j, path->data.ev_id, path));
            
            /* Find the maximum node in the sequence with all subsets of transitional nodes that include the current event */
            nodeM = pathfind(path->prev, path, path->data.ev_id);
            
            if (nodeM == NULL) {
                mexErrMsgTxt("ERROR nodeM problem\n");
            }
            
            DEBUG_PRINT((FDEBUG, "D: %p, %d, %f-%f\n", nodeM, nodeM->data.ev_id, nodeM->data.clk, path->data.clk));
            
            DEBUG_PRINT((FDEBUG, "Calculate original clock samples.\n"));
            if (nodeM != path) { /* calculate the original clock sample value */
                
                DEBUG_PRINT((FDEBUG, "(%p, %d)<--(%p, %d)\n", nodeM, nodeM->data.ev_id, path, path->data.ev_id));
                
                value = orig_clksv(path, nodeM);
                
                DEBUG_PRINT((FDEBUG, "Change %f from %f\n", path->data.clk, value));
                /*clock_debug(path->data.t_node->clk_samples, path->data.t_node->clk_samples->firstNode);*/
                
                
                assert(replace(path->data.t_node->clk_samples, path->data.clk, value));
                assert(path->data.clk == value);
                
                /* Change the clock sample to the original */
                /*if (replace(path->data.t_node->clk_samples, path->data.clk, value)) {*/
                    path->data.clk = value;
                /*}
                else
                    mexErrMsgTxt("The clocks not match ...\n");*/
            }
        }
    }
}
